package com.chujian.gateway.route;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.chujian.gateway.properties.DynamicRouteProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * @author ：yj
 * @date ：2020-07-30
 * Nacos 动态路由
 */
@Slf4j
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private final ApplicationEventPublisher eventPublisher;
    private final DynamicRouteProperties dynamicRouteProperties;
    private final ConfigService configService;

    /**
     * @param eventPublisher         事件发布器
     * @param nacosConfigManager     NacosConfigManager
     * @param dynamicRouteProperties 自定义动态路由配置
     */
    public NacosRouteDefinitionRepository(
            ApplicationEventPublisher eventPublisher,
            NacosConfigManager nacosConfigManager,
            DynamicRouteProperties dynamicRouteProperties
    ) {
        this.eventPublisher = eventPublisher;
        this.configService = nacosConfigManager.getConfigService();
        this.dynamicRouteProperties = dynamicRouteProperties;
        addListener();
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            String content = configService.getConfig(
                    dynamicRouteProperties.getDataId(),
                    dynamicRouteProperties.getGroupId(),
                    dynamicRouteProperties.getTimeOut());
            List<RouteDefinition> routeDefinitions = getListByStr(content);
            return Flux.fromIterable(routeDefinitions);
        } catch (NacosException e) {
            log.error("getRouteDefinitions by nacos error", e);
        }
        return Flux.fromIterable(CollUtil.newArrayList());
    }

    /**
     * 添加Nacos监听
     */
    private void addListener() {
        try {
            configService.addListener(
                    dynamicRouteProperties.getDataId(),
                    dynamicRouteProperties.getGroupId(),
                    new Listener() {
                        @Override
                        public Executor getExecutor() {
                            return null;
                        }

                        @Override
                        public void receiveConfigInfo(String configInfo) {
                            log.info("路由信息变更.....");
                            eventPublisher.publishEvent(new RefreshRoutesEvent(this));
                        }
                    });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        log.info("路由信息变更 save.....");
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        log.info("路由信息变更 delete.....");
        return null;
    }

    private List<RouteDefinition> getListByStr(String content) {
        if (StrUtil.isNotEmpty(content)) {
            return JSONObject.parseArray(content, RouteDefinition.class);
        }
        return new ArrayList<>(0);
    }
}
